﻿using System;
using System.Collections.Generic;
using System.Linq;

namespace ReportsFactory
{
    [Serializable()]
    public class Report
    {
        public static List<string> ValidOperands = new List<string> 
                                                    {
                                                        "=",
                                                        "<>",
                                                        ">",
                                                        ">=",
                                                        "<",
                                                        "<=",
                                                        "like",
                                                        "in",
                                                    };

        public string ID { get; set; }
        public string Name { get; set; }
        public string Owner { get; set; }
        public DateTime CreatedDate { get; set; }
        public bool IsPublic { get; set; }
        public bool IsNew { get; set; }
        public List<Table> Tables { get; set; }
        public bool IsCurrentUserOwner
        {
            get
            {
                return this.Owner.IsNull() || this.Owner.ToLower() == Common.Username.ToLower();
            }
        }

        public Report()
        {
            Tables = new List<Table>();
            ID = Guid.NewGuid().ToString();
            IsNew = true;
        }

        public bool RelationExist(string srcCol, string tgtCol, Table tgtTab)
        {
            foreach (var table in Tables)
            {
                bool exist = table.Relations.Where(c => c.SourceColumn.ColumnName.ToLower() == srcCol.ToLower() &&
                                                   c.TagetColumn.ColumnName.ToLower() == tgtCol.ToLower() &&
                                                   c.TargetTable.TableId == tgtTab.TableId).Any();

                if (exist == true)
                    return true;
            }

            return false;
        }

        public bool SaveReport()
        {
            var reports = Common.GetAllReportFileNames();
            var ser = new Serializer<Report>();
            foreach (string filename in reports)
            {
                Report rpt = new Report();
                rpt = ser.DeSerialize(Common.ReportsFolder + filename);
                if (rpt.ID == this.ID)
                {
                    this.IsNew = false;
                    ser.Serialize(this, Common.ReportsFolder + filename);
                    return true;
                }
            }

            ser.Serialize(this, Common.GetNewReportFileName());
            return true;
        }

        public Table GetTable(string connection, string tableName)
        {
            Table tab = (from item in this.Tables
                         where item.TableName.ToLower() == tableName.ToLower() &&
                         item.Connection.ToLower() == connection.ToLower()
                         select item).SingleOrDefault();
            if (tab.IsNull())
            {
                tab = new Table();
                tab.Connection = connection;
                tab.TableName = tableName;

                int? tableId = (from item in this.Tables
                                orderby item.TableId descending
                                select item.TableId).FirstOrDefault();

                if (!tableId.HasValue)
                    tableId = 0;

                tab.TableId = tableId.Value + 1;

                this.Tables.Add(tab);

            }

            return tab;
        }

        public Table GetTable(int tableId)
        {
            return this.Tables.Where(c => c.TableId == tableId).FirstOrDefault();
        }

        public bool RemoveTable(string connection, string tableName)
        {
            Table tab = (from item in this.Tables
                         where item.TableName.ToLower() == tableName.ToLower() &&
                         item.Connection.ToLower() == connection.ToLower()
                         select item).SingleOrDefault();
            if (tab.IsNotNull())
                this.Tables.Remove(tab);

            return true;
        }

        public class Table
        {
            public int TableId { get; set; }
            public string Connection { get; set; }
            public string TableName { get; set; }
            public List<Column> Columns { get; set; }
            public List<Relation> Relations { get; set; }

            public Table()
            {
                Columns = new List<Column>();
                Relations = new List<Relation>();
            }

            public bool ColumnExist(string columnName)
            {
                return Columns.Where(c => c.ColumnName.ToLower() == columnName.ToLower()).Any();
            }

            public Column GetColumn(string columnName)
            {
                var col = this.Columns.Where(c => c.ColumnName.ToLower() == columnName.ToLower()).FirstOrDefault();
                if (col.IsNull())
                {
                    col = new Column();
                    col.ColumnName = columnName;
                    this.Columns.Add(col);
                }

                return col;
            }

            public class Column
            {
                public string ColumnName { get; set; }

                private string _alias;
                public string Alias
                {
                    get
                    {
                        return _alias.IsEmpty() ? ColumnName : _alias;
                    }
                    set
                    {
                        _alias = value;
                    }

                }
                public List<Filter> Filters { get; set; }

                public Column()
                {
                    Filters = new List<Filter>();
                }
            }

            public class Filter
            {
                public string Operand { get; set; }
                public string FilterValue { get; set; }

                public Filter()
                {
                    throw new NotImplementedException();
                }

                public Filter(string _operand, string _filterValue)
                {
                    if (_operand.IsEmpty())
                        throw new ArgumentNullException("Operand");
                    else if (_filterValue.IsEmpty())
                        throw new ArgumentNullException("FilterValue");

                    if (!ValidOperands.Contains(_operand.ToLower()))
                        throw new ApplicationException("Invalid Operand. Operand should be in the following list:" + ValidOperands.ToString());

                    if (_operand.ToLower() == "like")
                        _filterValue = _filterValue.Replace("%", "");

                    Operand = _operand;
                    FilterValue = _filterValue;
                }
            }
        }

        public class Relation
        {
            public Table TargetTable { get; set; }
            public Table.Column TagetColumn { get; set; }
            public Table.Column SourceColumn { get; set; }

            public Relation()
            {
                TargetTable = new Table();
            }
        }

    }
}